/**
* @file resolver.go
* @name 依赖解析器
* @desc 使用语义化版本处理和冲突解决
* @version 0.1
* @date 2023-07-07
 */

package pkgman

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"nest/internal/pkgerrors"
	"nest/internal/utils"
	"path/filepath"
	"sort"
	"strings"

	"golang.org/x/mod/semver"
)

// 包元数据
type PackageMetadata struct {
	//  包名
	Name string `json:"name"`
	//  版本
	Version string `json:"version"`
	//  描述
	Description string `json:"description"`
	//  作者
	Author string `json:"author"`
	//  许可证
	License string `json:"license"`
	//  主页
	Homepage string `json:"homepage"`
	//  下载地址
	DownloadURL string `json:"download_url"`
	//  包校验
	Checksum string `json:"checksum"`
	//  依赖项
	Dependencies map[string]string `json:"dependencies"`
	Files        []string          `json:"files"`
}

// 依赖解析结果
type ResolvedDependency struct {
	Name    string
	Version string
	Path    string
}

/**
 * 解析包依赖
 * versionConstraint 版本约束
 */
func (pm *PackageManager) ResolveDependencies(packageName, versionConstraint string) ([]ResolvedDependency, error) {
	// 清理版本约束（移除前缀 v）
	if strings.HasPrefix(versionConstraint, "v") {
		versionConstraint = versionConstraint[1:]
	}

	// 获取可用版本
	versions, err := pm.GetAvailableVersions(packageName)
	if err != nil {
		return nil, fmt.Errorf("获取可用版本失败: %v", err)
	}

	// 查找匹配的最高版本
	var resolvedVersion string
	for i := len(versions) - 1; i >= 0; i-- {
		version := versions[i]
		// 移除前缀 v
		if strings.HasPrefix(version, "v") {
			version = version[1:]
		}
		if semver.Compare(version, versionConstraint) >= 0 {
			resolvedVersion = versions[i]
			break
		}
	}

	if resolvedVersion == "" {
		return nil, fmt.Errorf("找不到符合约束 %s 的版本", versionConstraint)
	}

	// 递归解析依赖
	resolvedDeps := make(map[string]ResolvedDependency)
	if err := pm.resolveDependenciesRecursive(packageName, resolvedVersion, resolvedDeps); err != nil {
		return nil, err
	}

	// 转换为切片
	result := make([]ResolvedDependency, 0, len(resolvedDeps))
	for _, dep := range resolvedDeps {
		result = append(result, dep)
	}

	return result, nil
}

// 获取包的可用版本
func (pm *PackageManager) GetAvailableVersions(packageName string) ([]string, error) {
	// 先检查有没有可用版
	if versions, ok := pm.availablePkgs[packageName]; ok {
		return versions, nil
	}
	// 从数据库中查询出包的信息
	var versionsJSON string
	err := pm.db.QueryRow(` select versions from packages where name = ? `, packageName).Scan(&versionsJSON)

	if err == nil {
		var versions []string
		if err := json.Unmarshal([]byte(versionsJSON), &versions); err != nil {
			return nil, fmt.Errorf("解析版本信息失败: %v", err)
		}
		pm.availablePkgs[packageName] = versions
		return versions, nil
	}

	if err != sql.ErrNoRows {
		return nil, fmt.Errorf("查询数据库失败: %v", err)
	}

	// 从远程索引获取版本
	versions, err := pm.fetchVersionsFromRemote(packageName)
	if err != nil {
		return nil, fmt.Errorf("从远程获取版本失败: %v", err)
	}
	// 保存到数据库，转成json字符串
	versionsJSONBytes, err := json.Marshal(versions)
	if err != nil {
		return nil, fmt.Errorf("序列化版本信息失败: %v", err)
	}
	versionsJSON = string(versionsJSONBytes)

	_, err = pm.db.Exec(`insert or replace into packages (name, versions) values (?, ?) `, packageName, versionsJSON)
	if err != nil {
		return nil, fmt.Errorf("保存版本信息失败: %v", err)
	}

	pm.availablePkgs[packageName] = versions
	return versions, nil
}

// 从远程索引获取版本
func (pm *PackageManager) fetchVersionsFromRemote(packageName string) ([]string, error) {

	// 实际实现中会调用索引 API
	resultJson, err := utils.HttpGet(utils.Api.Versions + "?packageName=" + packageName + "&version=latest" + "&token=token")
	if err != nil {
		return nil, pkgerrors.WrapError(err, pkgerrors.CodeInvalidNetwork, pkgerrors.LevelFatal, pkgerrors.CategoryNetwork, "网络链接错误")
	}
	result := utils.ReturnFun(resultJson)
	if !result.Success {
		return nil, pkgerrors.Error("获取版本信息失败")
	}
	dataInfo := result.Data.(map[string]interface{})
	// 这里简化为模拟获取
	/* versions := []string{
		"v1.0.0", "v1.0.1", "v1.1.0", "v1.2.0",
		"v2.0.0", "v2.1.0", "v2.1.1", "v2.2.0",
	} */
	versions := dataInfo["versions"].([]string)

	// 排序版本
	sort.Slice(versions, func(i, j int) bool {
		return semver.Compare(versions[i], versions[j]) < 0
	})

	return versions, nil
}

// 获取包元数据
func (pm *PackageManager) GetPackageMetadata(packageName, version string) (PackageMetadata, error) {
	// 检查缓存
	cacheKey := fmt.Sprintf("%s@%s", packageName, version)
	if metadata, ok := pm.metadataCache[cacheKey]; ok {
		return metadata, nil
	}

	// 从远程获取
	metadata, err := pm.fetchMetadataFromRemote(packageName, version)
	if err != nil {
		return PackageMetadata{}, fmt.Errorf("获取元数据失败: %v", err)
	}

	pm.metadataCache[cacheKey] = metadata
	return metadata, nil
}

// 从远程获取元数据
func (pm *PackageManager) fetchMetadataFromRemote(packageName, version string) (PackageMetadata, error) {
	// 实际实现中会调用索引 API

	metaDataStr, err := utils.HttpGet(utils.Api.Metadata + "?packageName=" + packageName + "&version=" + version)
	if err != nil {
		return PackageMetadata{}, pkgerrors.WrapError(err, pkgerrors.CodeInvalidNetwork, pkgerrors.LevelFatal, pkgerrors.CategoryNetwork, "网络链接错误")
	}

	//远程包的信息转为PackageMetadata
	packageMetadatasList := make(map[string]PackageMetadata)
	if err := json.Unmarshal([]byte(metaDataStr), &packageMetadatasList); err != nil {
		return PackageMetadata{}, fmt.Errorf("解析版本信息失败: %v", err)
	}
	metadata := packageMetadatasList[packageName]
	/* //远程包的信息转为PackageMetadata
	var metadata PackageMetadata
	err = yaml.Unmarshal([]byte(metaDataStr), &metadata)
	if err != nil {
		return pkgerrors.WrapError(err, pkgerrors.CodeInvalidPackage, pkgerrors.LevelFatal, pkgerrors.CategoryPackage, "获取"+packageName+"包信息错误")
	} */

	/* // 这里简化为模拟获取
	metadata := PackageMetadata{
		Name:        packageName,
		Version:     version,
		Description: "示例包描述",
		Author:      "示例作者",
		License:     "MIT",
		Homepage:    "https://example.com",
		DownloadURL: fmt.Sprintf("http://local.nest.cn/packages/%s-%s.egg", packageName, version),
		Checksum:    "sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890",
		Dependencies: map[string]string{
			"dependency1": ">=1.0.0",
			"dependency2": "^2.0.0",
		},
		Files: []string{"README.md", "LICENSE", "src/main.go"},
	} */

	return metadata, nil
}

// 递归解析依赖
func (pm *PackageManager) resolveDependenciesRecursive(packageName, version string, resolvedDeps map[string]ResolvedDependency) error {
	// 检查是否已解析
	key := fmt.Sprintf("%s@%s", packageName, version)
	if _, ok := resolvedDeps[key]; ok {
		return nil
	}

	// 获取元数据
	metadata, err := pm.GetPackageMetadata(packageName, version)
	if err != nil {
		return err
	}

	// 创建已解析依赖项
	dep := ResolvedDependency{
		Name:    packageName,
		Version: version,
		Path:    filepath.Join(pm.installDir, packageName, version),
	}

	// 记录已解析依赖
	resolvedDeps[key] = dep

	// 解析子依赖
	for depName, constraint := range metadata.Dependencies {
		// 清理版本约束
		if strings.HasPrefix(constraint, "v") {
			constraint = constraint[1:]
		}

		// 获取可用版本
		versions, err := pm.GetAvailableVersions(depName)
		if err != nil {
			return fmt.Errorf("获取依赖 %s 的可用版本失败: %v", depName, err)
		}

		// 查找匹配的最高版本
		var resolvedDepVersion string
		for i := len(versions) - 1; i >= 0; i-- {
			depVersion := versions[i]
			// 移除前缀 v
			if strings.HasPrefix(depVersion, "v") {
				depVersion = depVersion[1:]
			}
			if semver.Compare(depVersion, constraint) >= 0 {
				resolvedDepVersion = versions[i]
				break
			}
		}

		if resolvedDepVersion == "" {
			return fmt.Errorf("找不到符合约束 %s 的依赖 %s 版本", constraint, depName)
		}

		// 递归解析子依赖
		if err := pm.resolveDependenciesRecursive(depName, resolvedDepVersion, resolvedDeps); err != nil {
			return err
		}
	}

	return nil
}
